package net.wanderinghorse.jsonmessage.response;

import net.wanderinghorse.json.JSONArray;
import net.wanderinghorse.json.JSONObject;
import net.wanderinghorse.jsonmessage.AbstractRequestHandlerServlet;
import net.wanderinghorse.jsonmessage.Request;
import net.wanderinghorse.jsonmessage.Response;

import javax.servlet.http.HttpSession;
import java.util.Enumeration;

/**
 * Implements the serverSession response handler type, as described in the JSONMessage
 * library manual.
 *
 * BUGS:
 *
 * - When both "get" and "set" are specified, even though the "get" op is performed first,
 * the "get" output object has the _new_ values for all entries instead of the old values.
 * i have no clue why.  
 */
public class HttpServerSession extends AbstractRequestHandlerServlet {
    public HttpServerSession() {
        super(true);
    }

    /**
     * Implements the "get" operation described for this message type in the library manual.
     * @param sess The HTTP session.
     * @param reqPay Request payload. If it contains no array named "get" then this function has no side effects.
     * @param respPay Response payload object to populate with the response data.
     */
    private void handleGet( final HttpSession sess, final JSONObject reqPay, final JSONObject respPay ) {
        JSONArray toGet = reqPay.optJSONArray( "get" );
        if( null == toGet ) return;
        // Fetch vars...
        final Enumeration vars = sess.getAttributeNames();
        final JSONObject jo = new JSONObject();
        respPay.put("get", jo);
        final boolean doAll = (0==toGet.length());
        if( doAll ) {
            while( vars.hasMoreElements() ) {
                final String k = (String)vars.nextElement();
                final Object val = sess.getAttribute(k);
                jo.put( k, (null==val) ? JSONObject.NULL : val );
            }
        }
        else {
            for( int i = 0; i < toGet.length(); ++i ) {
                final String key = toGet.getString(i);
                if( (null == key) || key.isEmpty() ) continue;
                final Object val = sess.getAttribute(key);
                jo.put( key, (null==val) ? JSONObject.NULL : val );
            }
        }
    }

    /**
     * Implements the "set" operation described for this message type in the library manual.
     * @param sess The HTTP session.
     * @param reqPay Request payload. If it contains no object named "set" then this function has no side effects.
     * @param respPay Response payload object to populate with the response data.
     */
    private void handleSet( final HttpSession sess, final JSONObject reqPay, final JSONObject respPay ) {
        final JSONObject toSet = reqPay.optJSONObject( "set" );
        if( null == toSet ) return;
        final JSONObject jo = new JSONObject();
        respPay.put( "set", jo );
        final JSONArray keys = toSet.names();
        for( int i = 0; i < keys.length(); ++i ) {
            final String key = keys.get(i).toString();
            final Object val = toSet.opt(key);
            if( JSONObject.NULL.equals(val) ) {
                sess.removeAttribute( key );
            }
            else {
                sess.setAttribute(key, val);
            }
            jo.put( key, (null==val) ? JSONObject.NULL : val );
        }
    }

    @Override
    protected void doProcessResponse(final ServletInfo hreq, final Request req, final Response resp) throws Exception {
        final JSONObject inpay = this.getPayloadObject( req );
        if( null == inpay ) {
            this.setErrorState( resp, 1, "No operations were specified!" );
            return;
        }
        HttpSession hsess = hreq.getSession(true);
        JSONObject opay = new JSONObject();
        handleGet( hsess, inpay, opay );
        handleSet( hsess, inpay, opay );
        resp.setPayload( opay );
        if( inpay.optBoolean("id",false) ) {
            opay.put( "id", hsess.getId() );
        }
        if( inpay.optBoolean("clearSession",false) ) {
            hsess.invalidate();
            opay.put( "cleared", true );
            //hreq.removeCookie(new Cookie("JSESSIONID",""));
        }
    }
}
